import random
import time
import math
import win32api
import win32con

def cubic_bezier(p0, p1, p2, p3, num_points):
    """生成三次贝塞尔曲线路径点"""
    points = []
    for t in (i / (num_points - 1) for i in range(num_points)):
        x = (1 - t)**3 * p0[0] + 3 * (1 - t)**2 * t * p1[0] + 3 * (1 - t) * t**2 * p2[0] + t**3 * p3[0]
        y = (1 - t)**3 * p0[1] + 3 * (1 - t)**2 * t * p1[1] + 3 * (1 - t) * t**2 * p2[1] + t**3 * p3[1]
        points.append((x, y))
    return points

def generate_control_points(start, end, screen_w, screen_h):
    """生成带边界约束的贝塞尔曲线控制点"""
    dx = end[0] - start[0]
    dy = end[1] - start[1]
    
    # 计算垂直方向向量
    perp_dx = -dy
    perp_dy = dx
    
    # 处理零向量情况
    length = math.hypot(perp_dx, perp_dy)
    if length == 0:
        return (start, start, end, end)
    
    # 归一化垂直向量
    perp_dx /= length
    perp_dy /= length
    
    # 动态调整曲线强度
    max_intensity = min(screen_w, screen_h) * 0.15
    curve_intensity = math.hypot(dx, dy) * random.uniform(0.1, 0.3)
    curve_intensity = min(curve_intensity, max_intensity)
    
    # 边界约束函数
    def clamp(value, min_val, max_val):
        return max(min_val, min(value, max_val))
    
    # 生成控制点
    ctrl1 = (
        clamp(start[0] + dx * 0.25 + perp_dx * curve_intensity, 0, screen_w),
        clamp(start[1] + dy * 0.25 + perp_dy * curve_intensity, 0, screen_h)
    )
    ctrl2 = (
        clamp(start[0] + dx * 0.75 - perp_dx * curve_intensity, 0, screen_w),
        clamp(start[1] + dy * 0.75 - perp_dy * curve_intensity, 0, screen_h)
    )
    return ctrl1, ctrl2

def human_mouse_move(end_x, end_y, vtime ,num_points):
    """模拟人类鼠标移动核心函数"""
    # 获取屏幕尺寸
    screen_w = win32api.GetSystemMetrics(0) - 1
    screen_h = win32api.GetSystemMetrics(1) - 1

        
    try:
        start_x, start_y = win32api.GetCursorPos()
    except win32api.error:
        raise Exception("无法获取初始鼠标位置")
    
    # 约束目标位置
    end_x = max(0, min(end_x, screen_w))
    end_y = max(0, min(end_y, screen_h))
    
    # 生成控制点和路径
    start = (start_x, start_y)
    end = (end_x, end_y)
    ctrl1, ctrl2 = generate_control_points(start, end, screen_w, screen_h)
    points = cubic_bezier(start, ctrl1, ctrl2, end, num_points)
    
    # 添加随机扰动
    points = [
        (
            x + random.uniform(-0.5, 0.5),
            y + random.uniform(-0.5, 0.5)
        ) for x, y in points
    ]
    
    # 边界约束路径点
    points = [
        (max(0, min(x, screen_w)), 
        max(0, min(y, screen_h)))
        for x, y in points
    ]
    
    base_delay = vtime / len(points)
    MAX_STEP = 3  # 单次移动最大步长
    
    # 执行移动
    for i, (target_x, target_y) in enumerate(points):
        try:
            current_x, current_y = win32api.GetCursorPos()
        except win32api.error:
            break
        
        # 最终点强制到达目标位置
        if i == len(points) - 1:
            target_x = end_x
            target_y = end_y
        
        # 修改步长计算方式
        total_dx = target_x - current_x
        total_dy = target_y - current_y
        distance = math.hypot(total_dx, total_dy)
        steps = max(1, int(math.ceil(distance / MAX_STEP)))
        step_dx = total_dx / steps
        step_dy = total_dy / steps
        
        # 分步移动（使用累积增量）
        accumulated_dx = 0
        accumulated_dy = 0
        for step in range(steps):
            # 计算理论增量
            theory_dx = step_dx * (step + 1) - accumulated_dx
            theory_dy = step_dy * (step + 1) - accumulated_dy
            
            # 四舍五入处理
            actual_dx = int(round(theory_dx))
            actual_dy = int(round(theory_dy))
            
            # 执行移动并记录累积量
            if actual_dx != 0 or actual_dy != 0:
                win32api.mouse_event(
                    win32con.MOUSEEVENTF_MOVE,
                    actual_dx,
                    actual_dy,
                    0,
                    0
                )
                accumulated_dx += actual_dx
                accumulated_dy += actual_dy
            
            time.sleep(base_delay / steps * random.uniform(0.9, 1.1))

    # 增强最终校正（新增精确补偿）
    for _ in range(5):  # 增加至5次尝试
        current_x, current_y = win32api.GetCursorPos()
        dx = end_x - current_x
        dy = end_y - current_y
        if dx == 0 and dy == 0:
            break
        
        # 小距离精确移动
        while abs(dx) > 0 or abs(dy) > 0:
            step_x = 1 if dx > 0 else -1 if dx < 0 else 0
            step_y = 1 if dy > 0 else -1 if dx < 0 else 0
            win32api.mouse_event(win32con.MOUSEEVENTF_MOVE, step_x, step_y, 0, 0)
            dx -= step_x
            dy -= step_y
            time.sleep(0.005)

def get_valid_coordinate(prompt, max_value):
    """获取有效坐标输入"""
    while True:
        try:
            value = int(input(prompt))
            if 0 <= value <= max_value:
                return value
            print(f"输入超出范围 (0-{max_value})，请重新输入")
        except ValueError:
            print("请输入有效的整数")



if __name__ == "__main__":
    # 获取屏幕尺寸
    screen_w = win32api.GetSystemMetrics(0) - 1
    screen_h = win32api.GetSystemMetrics(1) - 1
    
    print(f"当前屏幕尺寸：{screen_w}x{screen_h}")
    print("请输入目标坐标：")
    
    # 获取用户输入
    target_x = 100
    target_y = 900
    vtime = 0.3
    num_points = 500

    
    # 执行移动
    try:
        print(f"开始移动到 ({target_x}, {target_y})")
        human_mouse_move(target_x, target_y, vtime, num_points)
        final_pos = win32api.GetCursorPos()
        print(f"移动完成，最终位置: {final_pos}")
    except Exception as e:
        print(f"移动过程中出现错误: {str(e)}")